/*
 ============================================================================
 Name        : usrSimpleApp.c
 Author      :
 Version     :
 Copyright   : Your copyright notice
 Description : Hello World in C, Ansi-style
 ============================================================================
 */

#define _GNU_SOURCE
#include <sched.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <semaphore.h>
#include <error.h>
#include <malloc.h>
#include <assert.h>
#include <fcntl.h>
#include <getopt.h>
#include <stdint.h>
#include <string.h>
#include <time.h>

#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/select.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

#include "reg_rw.h"
#include "dma_from_device.h"
#include "pspHead.h"

extern unsigned long long g_word;

extern void * xdmaMemAllocBuf(unsigned int BufIndex, unsigned int align,
		unsigned int nBytes);

#define RIO_RECV_LEVEL (1024)
asyn_inputmsg g_netRecvUsrInfo1[RIO_RECV_LEVEL];
asyn_inputmsg g_netRecvUsrInfo2[RIO_RECV_LEVEL];
asyn_inputmsg g_netRecvUsrInfo3[RIO_RECV_LEVEL];
asyn_inputmsg g_netRecvUsrInfo4[RIO_RECV_LEVEL];
asyn_inputmsg g_netRecvUsrInfo5[RIO_RECV_LEVEL];
asyn_inputmsg g_netRecvUsrInfo6[RIO_RECV_LEVEL];

u32 gxRecvUsrInfoWptr1 = 0;
u32 gxRecvUsrInfoWptr2 = 0;
u32 gxRecvUsrInfoWptr3 = 0;
u32 gxRecvUsrInfoWptr4 = 0;
u32 gxRecvUsrInfoWptr5 = 0;
u32 gxRecvUsrInfoWptr6 = 0;

u32 gxRecvUsrInfoRptr1 = 0;
u32 gxRecvUsrInfoRptr2 = 0;
u32 gxRecvUsrInfoRptr3 = 0;
u32 gxRecvUsrInfoRptr4 = 0;
u32 gxRecvUsrInfoRptr5 = 0;
u32 gxRecvUsrInfoRptr6 = 0;

u32 gxRecvUsrInfoTotal1 = 0;
u32 gxRecvUsrInfoTotal2 = 0;
u32 gxRecvUsrInfoTotal3 = 0;
u32 gxRecvUsrInfoTotal4 = 0;
u32 gxRecvUsrInfoTotal5 = 0;
u32 gxRecvUsrInfoTotal6 = 0;

sem_t gSemInput1;
sem_t gSemInput2;
sem_t gSemInput3;
sem_t gSemInput4;
sem_t gSemInput5;
sem_t gSemInput6;

int run_xdma_flag;

void asyn_bslWaitInputData(int chainNum)
{
	switch(chainNum)
	{
	case 1:
		sem_wait(&gSemInput1);
		break;
	case 2:
		sem_wait(&gSemInput2);
		break;
	case 3:
		sem_wait(&gSemInput3);
		break;
	case 4:
		sem_wait(&gSemInput4);
		break;
	case 5:
		sem_wait(&gSemInput5);
		break;
	case 6:
		sem_wait(&gSemInput6);
		break;
	default:
		break;
	}
}

int asyn_bslGetInputData(int chainNum,void* msg)
{
	struct asyn_InputInfoMsg *pInfoMsg = (struct asyn_InputInfoMsg *)msg;
	unsigned int wptr;
	unsigned int rptr;

	switch(chainNum)
	{
	case 1:
		rptr = gxRecvUsrInfoRptr1;
		wptr = gxRecvUsrInfoWptr1;
		break;
	case 2:
		rptr = gxRecvUsrInfoRptr2;
		wptr = gxRecvUsrInfoWptr2;
		break;
	case 3:
		rptr = gxRecvUsrInfoRptr3;
		wptr = gxRecvUsrInfoWptr3;
		break;
	case 4:
		rptr = gxRecvUsrInfoRptr4;
		wptr = gxRecvUsrInfoWptr4;
		break;
	case 5:
		rptr = gxRecvUsrInfoRptr5;
		wptr = gxRecvUsrInfoWptr5;
		break;
	case 6:
		rptr = gxRecvUsrInfoRptr6;
		wptr = gxRecvUsrInfoWptr6;
		break;
	default:
		break;
	}

	if (rptr != wptr)
	{
		switch(chainNum)
		{
		case 1:
			pInfoMsg->src = g_netRecvUsrInfo1[rptr].src;
			pInfoMsg->tsize= g_netRecvUsrInfo1[rptr].tsize;
			rptr = (rptr + 1) & (RIO_RECV_LEVEL - 1);
			gxRecvUsrInfoRptr1 = rptr;
			gxRecvUsrInfoTotal1++;
			break;
		case 2:
			pInfoMsg->src = g_netRecvUsrInfo2[rptr].src;
			pInfoMsg->tsize = g_netRecvUsrInfo2[rptr].tsize;
			rptr = (rptr + 1) & (RIO_RECV_LEVEL - 1);
			gxRecvUsrInfoRptr2 = rptr;
			gxRecvUsrInfoTotal2++;
			break;
		case 3:
			pInfoMsg->src = g_netRecvUsrInfo3[rptr].src;
			pInfoMsg->tsize = g_netRecvUsrInfo3[rptr].tsize;
			rptr = (rptr + 1) & (RIO_RECV_LEVEL - 1);
			gxRecvUsrInfoRptr3 = rptr;
			gxRecvUsrInfoTotal3++;
			break;
		case 4:
			pInfoMsg->src = g_netRecvUsrInfo4[rptr].src;
			pInfoMsg->tsize = g_netRecvUsrInfo4[rptr].tsize;
			rptr = (rptr + 1) & (RIO_RECV_LEVEL - 1);
			gxRecvUsrInfoRptr4 = rptr;
			gxRecvUsrInfoTotal4++;
			break;
		case 5:
			pInfoMsg->src = g_netRecvUsrInfo5[rptr].src;
			pInfoMsg->tsize = g_netRecvUsrInfo5[rptr].tsize;
			rptr = (rptr + 1) & (RIO_RECV_LEVEL - 1);
			gxRecvUsrInfoRptr5 = rptr;
			gxRecvUsrInfoTotal5++;
			break;
		case 6:
			pInfoMsg->src = g_netRecvUsrInfo6[rptr].src;
			pInfoMsg->tsize= g_netRecvUsrInfo6[rptr].tsize;
			rptr = (rptr + 1) & (RIO_RECV_LEVEL - 1);
			gxRecvUsrInfoRptr6 = rptr;
			gxRecvUsrInfoTotal6++;
			break;
		default:
			break;
		}
		return 1;
	}
	return 0;
}

void asyn_xdma_drvrecv()
{
	int res = 0;
	void *dstAddr = 0;
	unsigned int baseaddr;
	unsigned int size;
	unsigned int chainNum;
	int lastbianhao[7],bianhao[7];

	int fpga_fd = open("/dev/xdma0_c2h_0", O_RDWR | O_NONBLOCK);
	int bypass=open("/dev/xdma0_bypass", O_RDWR | O_SYNC);

	if(fpga_fd<0||bypass<0)
	{
		printf("Open device error! check your backup card or driver\n");
		return;
	}

	while (run_xdma_flag)
    {
		size=0;
		baseaddr=0;
		chainNum=0;
		//read io pass
		res = reg_bypass_rw(bypass,0);

		if(g_word != 0x0)
		{
//			printf("0x%llx\n",g_word);
			chainNum = (g_word>>56)&0xf;
			bianhao[chainNum] = (g_word>>60)&0xf;
#if 1
			if(bianhao[chainNum]==0)
			{
				lastbianhao[chainNum]=-1;
			}
			if(bianhao[chainNum]-lastbianhao[chainNum]!=1)
			{
				printf("error bianhao is %d lastbianhao is %d\n",bianhao[chainNum],lastbianhao[chainNum]);
				lastbianhao[chainNum]=bianhao[chainNum];
			}
			else
			{
				lastbianhao[chainNum]=bianhao[chainNum];
			}
#endif
			size=g_word&0xffffffff;
			baseaddr=((g_word>>44)&0xfff)<<20;
		}

		//use dma to get data
		if(size!=0)
		{
			dstAddr = (void*) xdmaMemAllocBuf(0, 4096, size);
			read_dma(fpga_fd,baseaddr, size, dstAddr);

			switch(chainNum)
			{
			case 1:
				g_netRecvUsrInfo1[gxRecvUsrInfoWptr1].src = dstAddr;
				g_netRecvUsrInfo1[gxRecvUsrInfoWptr1].tsize = size;
				gxRecvUsrInfoWptr1 = (gxRecvUsrInfoWptr1 + 1) & (RIO_RECV_LEVEL - 1);
				sem_post(&gSemInput1);
				break;
			case 2:
				g_netRecvUsrInfo2[gxRecvUsrInfoWptr2].src = dstAddr;
				g_netRecvUsrInfo2[gxRecvUsrInfoWptr2].tsize = size;
				gxRecvUsrInfoWptr2 = (gxRecvUsrInfoWptr2 + 1) & (RIO_RECV_LEVEL - 1);
				sem_post(&gSemInput2);
				break;
			case 3:
				g_netRecvUsrInfo3[gxRecvUsrInfoWptr3].src = dstAddr;
				g_netRecvUsrInfo3[gxRecvUsrInfoWptr3].tsize = size;
				gxRecvUsrInfoWptr3 = (gxRecvUsrInfoWptr3 + 1) & (RIO_RECV_LEVEL - 1);
				sem_post(&gSemInput3);
				break;
			case 4:
				g_netRecvUsrInfo4[gxRecvUsrInfoWptr4].src = dstAddr;
				g_netRecvUsrInfo4[gxRecvUsrInfoWptr4].tsize = size;
				gxRecvUsrInfoWptr4 = (gxRecvUsrInfoWptr4 + 1) & (RIO_RECV_LEVEL - 1);
				sem_post(&gSemInput4);
				break;
			case 5:
				g_netRecvUsrInfo5[gxRecvUsrInfoWptr5].src = dstAddr;
				g_netRecvUsrInfo5[gxRecvUsrInfoWptr5].tsize = size;
				gxRecvUsrInfoWptr5 = (gxRecvUsrInfoWptr5 + 1) & (RIO_RECV_LEVEL - 1);
				sem_post(&gSemInput5);
				break;
			case 6:
				g_netRecvUsrInfo6[gxRecvUsrInfoWptr6].src = dstAddr;
				g_netRecvUsrInfo6[gxRecvUsrInfoWptr6].tsize = size;
				gxRecvUsrInfoWptr6 = (gxRecvUsrInfoWptr6 + 1) & (RIO_RECV_LEVEL - 1);
				sem_post(&gSemInput6);
				break;
			default:
				break;
			}
		}
	}
	close(fpga_fd);
	close(bypass);
}

int asyn_xdma_drvsend(void *srcAddr, unsigned int size,int flag) {
	unsigned int baseaddr = 0x1000;
	char diaodu[5000];
	char *pcXiankong;
	char *psrc;
	int count=0;
	int qtx_count=0;
	int last_count=0;
	int qtx_last_count=0;
	int total_size=0;
	int i,j;
	int fpga_fd = open("/dev/xdma0_h2c_0", O_RDWR);
	if(fpga_fd<0)
	{
		return -1;
	}
//	if(flag==1)
//	{
//		baseaddr = 0x8000000;
//		diaodu[0]=0xab;
//		diaodu[1]=0xab;
//		diaodu[2]=0xcd;
//		diaodu[3]=0xcd;
//		diaodu[4]=0xef;
//		diaodu[5]=0xef;
//		diaodu[6]=0x5a;
//		diaodu[7]=0x5a;
//		memcpy((char*)diaodu+8,srcAddr,2048);
//		diaodu[2056]=0xab;
//		diaodu[2057]=0xab;
//		diaodu[2058]=0xcd;
//		diaodu[2059]=0xcd;
//		diaodu[2060]=0xef;
//		diaodu[2061]=0xef;
//		diaodu[2062]=0xa5;
//		diaodu[2063]=0xa5;
//		write_dma(fpga_fd, baseaddr, 2064, (char*)diaodu);
//	}

	if(flag==1)
	{
		baseaddr = 0x8000000;
	}
	else
	{
		baseaddr = 0x1000;
	}
//	else
//	{
		pcXiankong=(char*)malloc(size+32);

//		baseaddr = 0x1000;
		pcXiankong[0]=0xab;
		pcXiankong[1]=0xab;
		pcXiankong[2]=0xcd;
		pcXiankong[3]=0xcd;
		pcXiankong[4]=0xef;
		pcXiankong[5]=0xef;
		pcXiankong[6]=0x5a;
		pcXiankong[7]=0x5a;
		memcpy((char*)pcXiankong+8,srcAddr,size);
		pcXiankong[size+8]=0xab;
		pcXiankong[size+9]=0xab;
		pcXiankong[size+10]=0xcd;
		pcXiankong[size+11]=0xcd;
		pcXiankong[size+12]=0xef;
		pcXiankong[size+13]=0xef;
		pcXiankong[size+14]=0xa5;
		pcXiankong[size+15]=0xa5;

		total_size=size+16;
		qtx_count=total_size/4096;
		for(j=0;j<qtx_count;j++)
		{
			for(i=0;i<2;i++)
			{
				psrc=pcXiankong+i*2048+j*4096;
				write_dma(fpga_fd, baseaddr, 2048, psrc);
			}
			usleep(5);
		}
		qtx_last_count=total_size%4096;


		count=qtx_last_count/2048;
		last_count=qtx_last_count%2048;
		for(i=0;i<count;i++)
		{
			psrc=pcXiankong+i*2048+qtx_count*4096;
			write_dma(fpga_fd, baseaddr, 2048, psrc);
		}
		psrc=pcXiankong+count*2048+qtx_count*4096;
		write_dma(fpga_fd, baseaddr, last_count, psrc);
		free(pcXiankong);
//	}
	close(fpga_fd);
	return 0;
}
